package com.zxf.crypt.advice;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.IoUtil;
import com.zxf.crypt.anno.ZxfDecryptRequest;
import com.zxf.crypt.constant.AlgorithmType;
import com.zxf.crypt.exception.ZxfCryptException;
import com.zxf.crypt.util.CryptUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;

import java.io.IOException;
import java.lang.reflect.Type;

/**
 * 请求数据接收处理，对使用了 @DecryptRequest 注解的方法的数据进行解密，只对 @RequestBody 参数有效
 *
 * @author zxf
 */
@RestControllerAdvice
public class DecryptRequestBodyAdvice implements RequestBodyAdvice {

    @Value("${com.zxf.crypt.DES.KEY}")
    private String DES_KRY = "";

    @Value("${com.zxf.crypt.DES_3.KEY}")
    private String DES_3_KRY = "";

    @Value("${com.zxf.crypt.AES.KEY}")
    private String AES_KRY = "";

    @Value("${com.zxf.crypt.RSA.PUBLIC_KEY}")
    private String RSA_PUBLIC_KEY = "";

    @Value("${com.zxf.crypt.RSA.PRIVATE_KEY}")
    private String RSA_PRIVATE_KEY = "";

    /**
     * 该方法用于判断当前请求，要不要执行 beforeBodyRead 中的方法
     *
     * @param methodParameter
     * @param targetType
     * @param converterType
     * @return
     */
    @Override
    public boolean supports(MethodParameter methodParameter,
                            Type targetType,
                            Class<? extends HttpMessageConverter<?>> converterType) {
        return NeedCrypt.isNeedDecrypt(methodParameter);
    }

    /**
     * @param inputMessage  客户端请求数据
     * @param parameter     方法的参数对象
     * @param targetType    方法的参数类型
     * @param converterType http请求消息转换器
     * @return
     * @throws IOException
     */
    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage,
                                           MethodParameter parameter,
                                           Type targetType,
                                           Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
        //解密后的数据
        String deData = null;
        //获取加密数据
        String enData = IoUtil.readUtf8(inputMessage.getBody());
        ZxfDecryptRequest decryptRequest = parameter.getMethod().getAnnotation(ZxfDecryptRequest.class);
        AlgorithmType type = decryptRequest.type();
        //获取加密类型

        switch (type) {
            case RSA:
                try {
                    deData = CryptUtil.decryptRSA(enData, RSA_PRIVATE_KEY);
                } catch (Exception e) {
                    throw new ZxfCryptException("SRA 加密文本格式不正确或者秘钥识别错误");
                }
                break;
            case DES:
                try {
                    deData = CryptUtil.decryptDES(enData, DES_KRY);
                } catch (Exception e) {
                    throw new ZxfCryptException("DES 加密文本格式不正确或者秘钥识别错误");
                }
                break;
            case Base64:
                deData = Base64.decodeStr(enData);
                break;
            case MD5:
                throw new ZxfCryptException("MD5加密方式不能进行解密操作...");
            case DES_3:
                try {
                    deData = CryptUtil.decryptDES_3(enData, DES_3_KRY);
                } catch (Exception e) {
                    throw new ZxfCryptException("3DES 加密文本格式不正确或者秘钥识别错误");
                }
                break;
            case AES:
                try {
                    deData = CryptUtil.decryptAES(enData, AES_KRY);
                } catch (Exception e) {
                    throw new ZxfCryptException("RSA 加密文本格式不正确或者秘钥识别错误");
                }
                break;
            default:
        }
        return new DecryptHttpInputMessage(inputMessage, deData);
    }

    @Override
    public Object afterBodyRead(Object body,
                                HttpInputMessage inputMessage,
                                MethodParameter parameter,
                                Type targetType,
                                Class<? extends HttpMessageConverter<?>> converterType) {
        return body;
    }

    @Override
    public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return body;
    }
}
